<template>
  <Layout>

    <template #header>
      <el-button type="primary" size="mini" @click="stop('edge1')">启动停止第一条线</el-button>
      <el-button type="primary" size="mini" @click="stop('edge2')">启动停止第二条线</el-button>
      <el-button type="primary" size="mini" @click="run = !run">open Drawer</el-button>
      <el-button type="primary" size="mini" @click="save">save</el-button>

    </template>

    <template #asider>
      <itemPanel />
    </template>

    <div id="mountNode">
      <ToolBar :graph="graph" @search="search" :searchParams="searchParams" @prev="prev" @next="next" />
      <context-menu ref="contextMenu" :graph="graph" />
    </div>

    <Drawer :visible.sync="visible" :graph="graph" :graph-node="graphNode" @drawer-update="drawerUpdate" />

  </Layout>
</template>

<script>
import ItemPanel from "@/components/itemPanel";
import Drawer from "@/components/Drawer";
import Layout from "@/components/layout";
import ToolBar from "@/components/ToolBar";
import ContextMenu from "@/components/ContextMenu";
import G6 from '@antv/g6';
import { each } from '@antv/util';
import { uuid } from '@/utils';
import registerFactory from "@/graph";

registerFactory(G6);
export default {
  components: { Layout, ItemPanel, Drawer, ToolBar, ContextMenu },
  name: "App",
  data() {
    return {
      graph: {},
      graphNode: {},
      containerSize: [0, 0],
      run: true,
      visible: false,
      searchParams: {
        step: 0,
        stack: []
      }
    };
  },
  mounted() {
    this.initGraph();
    this.linstenEvent();
    this.graph.read({
      nodes: [
        {
          id: '1', x: 200, y: 100, label: 'shapeType', type: 'circle-node',
          style: { r: 50, stroke: '#fff', fill: '#65b586' },
          labelCfg: { style: { fill: '#fff', stroke: '#ccc', textAlign: 'center' } },
          anchorPointStyles: { r: 4, fill: '#fff', stroke: '#1890FF', lineWidth: 1 },
          data: { description: 'the is a circle' }
        },
        {
          id: '2', x: 800, y: 100, type: 'rect-node', label: 'rect',
          style: { width: 180, height: 60, lineWidth: 2, fill: '#65b586', stroke: '#fff', },
          labelCfg: { style: { lineWidth: 2, fontSize: 18, fill: '#ff6900', stroke: '#ccc', textAlign: 'center' } },
          data: { description: 'the is a rect' }
        },
        {
          id: '3', x: 200, y: 300, type: 'diamond-node', label: 'diamond',
          style: { width: 160, height: 100, fill: '#65b586', stroke: '#65b586' },
          labelCfg: { style: { lineWidth: 2, fontSize: 18, fill: '#fff', stroke: '#ccc', textAlign: 'center' } }
        },
        {
          id: '4', x: 800, y: 330, type: 'triangle-node', label: 'triangle', direction: 'up',
          style: { width: 160, height: 200, fill: '#65b586', lineWidth: 0, },
          labelCfg: { style: { lineWidth: 2, fontSize: 18, fill: '#fff', stroke: '#ccc', textAlign: 'center' } }
        },
        {
          id: '5', x: 200, y: 450, type: 'ellipse-node', label: 'ellipse',
          style: { rx: 100, ry: 30, stroke: '#fff', fill: '#65b586' },
          labelCfg: { style: { lineWidth: 2, fontSize: 18, fill: '#fff', stroke: '#ccc', textAlign: 'center' } },
        },
        {
          id: '6', x: 400, y: 430, type: 'rect-node', label: 'rect',
          style: { width: 180, height: 60, lineWidth: 2, fill: '#65b586', stroke: '#fff', },
          labelCfg: { lineWidth: 2, fontSize: 18, fill: '#fff', stroke: '#ccc', textAlign: 'center' }
        },
        {
          id: 'icon', x: 500, y: 100, type: 'icon-node', icon: '警报', label: '警报',
          style: { r: 40, stroke: '#fff', fill: '#F3F4F6', cursor: 'move', },
          iconCfg: { width: 60, height: 60, fill: '#ff4500' },
          labelCfg: { style: { fill: '#333', stroke: '#ccc', textAlign: 'center', lineWidth: 2 } },
          anchorPointStyles: { r: 4, fill: '#fff', stroke: '#1890FF', lineWidth: 1 },
        },
      ],
      edges: [
        {
          id: 'edge1', source: '1', target: '2', sourceAnchor: 3, label: 'circle join rect', type: 'cubic-edge', animate: true,
          labelCfg: { position: 'left', autoRotate: true, style: { stroke: 'white', fill: '#722ed1', lineWidth: 10 } }, ball: { stroke: 'red', fill: 'red', r: 5 },
        },
        {
          id: 'edge2', ball: { stroke: 'red', fill: 'red', r: 5 },
          source: '3', target: '4', sourceAnchor: 3, label: 'circle join rect', type: 'polyline-edge', animate: true,
        },
        {
          id: 'edge3', source: '2', target: '5', sourceAnchor: 3, label: 'circle join rect', type: 'quadratic-edge', animate: true,
          labelCfg: { position: 'left', autoRotate: true, style: { stroke: 'white', fill: '#722ed1', lineWidth: 10 } }, ball: { stroke: 'red', fill: 'red', r: 5 },
        }
      ],
    });
  },
  methods: {
    initGraph() {
      const [width, height] = [document.body.clientWidth - 240, document.body.clientHeight - 100];
      const tooltip = new G6.Tooltip({
        offsetX: 10,
        offsetY: 0,
        fixToNode: [0.8, 0.5],
        itemTypes: ['node'],
        getContent: (e) => {
          const outDiv = document.createElement('div');
          outDiv.style.width = 'fit-content';
          const { data = {} } = e.item.getModel();
          if (!data.description) { }
          outDiv.innerHTML = `
            <h4>提示信息</h4>
            <ul>
              <li>节点类型: ${e.item.getType()}</li>
              <li>描述信息: ${data?.description || ''}</li>
            </ul>`;
          return outDiv;
        },
      });
      const graph = new G6.Graph({
        container: 'mountNode',
        enabledStack: true,
        width,
        height,
        groupByTypes: false,
        animate: true,
        animateCfg: { duration: 500, easing: 'easeLinear' },
        modes: {
          default: [
            'zoom-canvas',
            'drag-combo',
            'drag-canvas',
            'hover-node',
            'select-node',
            'drag-shadow-node',
          ],
        },
        defaultNode: { type: 'rect-node', },
        defaultEdge: { type: 'cubic-edge', },
        plugins: [new G6.Grid(), tooltip,],
      });
      this.graph = graph;
      this.containerSize = [width, height];
      this.resize();
    },
    search(keywords) {
      const { graph } = this;
      this.searchParams.stack = [];
      const nodes = graph.getNodes();
      each(nodes, node => {
        if (!keywords) {
          return graph.setItemState(node, 'selected', false);
        }
        if (node.getModel().label.includes(keywords)) {
          graph.setItemState(node, 'selected', true);
          this.searchParams.stack.push(node);
        } else {
          graph.setItemState(node, 'selected', false);
        }
      });
      console.log(this.searchParams.stack);

      this.searchParams.stack.length && this.focusItem(this.searchParams.stack[0]);
    },
    prev() {
      const { stack } = this.searchParams;
      this.searchParams.step -= 1;
      if (this.searchParams.step < 0) this.searchParams.step = stack.length - 1;
      this.focusItem(stack[this.searchParams.step]);
    },
    next() {
      const { stack } = this.searchParams;
      this.searchParams.step += 1;
      if (this.searchParams.step > stack.length - 1) this.searchParams.step = 0;
      this.focusItem(stack[this.searchParams.step]);
    },
    focusItem(node) {
      const { graph } = this;
      const { x, y } = node.getModel();
      graph.focusItem(node, true, {
        x,
        y,
        duration: 500,
        easing: 'easeLinear',

      });
    },
    linstenEvent() {
      const { graph } = this;
      graph.on('drop', e => {
        const { originalEvent } = e;
        if (!originalEvent.dataTransfer) return;
        const transferData = originalEvent.dataTransfer.getData('dragComponent');
        if (!transferData) return;
        const item = JSON.parse(transferData);
        const { x, y } = e;
        graph.addItem('node', {
          id: `node-${uuid()}`,
          x,
          y,
          label: item.label,
          icon: item.label,
          iconName: item.className,
          type: `icon-node`,
          style: { r: 40, stroke: '#fff', fill: '#65b586', cursor: 'move', },
          iconCfg: { width: 60, height: 60, fill: '#E0E7FF' },
          labelCfg: { style: { fill: '#333', stroke: '#ccc', textAlign: 'center', lineWidth: 2 } },
          anchorPointStyles: { r: 4, fill: '#fff', stroke: '#1890FF', lineWidth: 1 },
        });
      });

      graph.on('node-click', ({ item, model }) => {
        if (!model.hasOwnProperty('id')) return;
        this.graphNode = item;
        this.visible = true;
      });

      graph.on('node-click-clear', (e) => {
        this.formInfo = {};
        this.visible = false;
      });

      graph.on("contextmenu", (e) => {
        e.preventDefault();
        this.$refs.contextMenu.onMenuShow(e)
      });
    },
    drawerUpdate(attrs) {
      const { graph, graphNode } = this;

      graph.updateItem(graphNode, attrs);
    },
    stop(id = 'edge1') {
      const edge = this.graph.findById(id);
      const model = edge.get('model');
      edge.set('model', { ...model, animate: !model.animate });
      edge.setState('running', !model.animate);
    },
    resize() {
      let timer = null;
      let [width, height] = this.containerSize;

      window.onresize = () => {
        width = document.body.clientWidth - 240
        height = document.body.clientHeight - 100;
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => {
          this.graph.changeSize(width, height);
        }, 250);
      };
      this.containerSize = [width, height];
    },
    save() {
      const data = this.graph.save();
      console.log(data);
    },
  },
};
</script>

<style lang="scss">
#mountNode {
  position: relative;
  z-index: 0;
  background: #fff;
  overflow: hidden;
}
</style>
